/*
 * Copyright (c) 2018-present, lmyooyo@gmail.com.
 *
 * This source code is licensed under the GPL license found in the
 * LICENSE file in the root directory of this source tree.
 */
package com.zhg.videorecord.presenter.impl

import android.content.Context
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.os.Build
import android.text.TextUtils
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.TextureView
import androidx.annotation.RequiresApi
import com.lmy.codec.pipeline.impl.GLEventPipeline
import com.lmy.codec.texture.impl.filter.BaseFilter
import com.zhg.videorecord.collect.CameraSurfaceWrapper
import com.zhg.videorecord.collect.CameraWrapper
import com.zhg.videorecord.encoder.Encoder
import com.zhg.videorecord.encoder.impl.AudioEncoderImpl
import com.zhg.videorecord.entity.CodecContext
import com.zhg.videorecord.helper.CodectUtil
import com.zhg.videorecord.helper.MuxerFactory
import com.zhg.videorecord.helper.TLog
import com.zhg.videorecord.helper.VideoCoverUtil
import com.zhg.videorecord.muxer.Muxer
import com.zhg.videorecord.presenter.VideoRecorder

/**
 * 视频录制的总控，从camera的预览，opengl渲染，到编码，合成
 */
class VideoRecorderV2Impl(ctx: Context
) : VideoRecorder, Encoder.OnPreparedListener {



    enum class Status {
        IDL, PREPARED, STARTED
    }

    private var context: CodecContext = CodecContext(ctx)
    private var encoder: Encoder? = null
    private var audioEncoder: Encoder? = null
    private var cameraWrapper: CameraSurfaceWrapper? = null
    private var muxer: Muxer? = null
    private var onStateListener: VideoRecorder.OnStateListener? = null
    private var sufaceView: SurfaceView? = null
    private var surfaceHolder:SurfaceHolder?=null;
    private var status: Status = Status.IDL
    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    override fun prepare() {
        if (TextUtils.isEmpty(context.ioContext.path)) {
            throw RuntimeException("context.ioContext.path can not be null!")
        }
        if (null == cameraWrapper) {
            cameraWrapper = CameraSurfaceWrapper.open(context, this)

        }

        sufaceView?.holder?.addCallback(object : SurfaceHolder.Callback{
            override fun surfaceCreated(holder: SurfaceHolder) {
                surfaceHolder=holder;
                startPreview()
                TLog.i("surfaceCreated")

            }

            override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
                updatePreview(width, height)
            }

            override fun surfaceDestroyed(holder: SurfaceHolder) {
                stop()
            }

        })

    }

    override fun prepared(): Boolean {
        return Status.PREPARED == status
    }

    override fun started(): Boolean {
        return Status.STARTED == status
    }

    override fun start() {
        if (Status.PREPARED != status) {
            throw IllegalStateException("The recorder is not prepare yet.")
        }
        encoder?.start()
        audioEncoder?.start()
        status = Status.STARTED
    }

    override fun pause() {
        if (Status.STARTED != status) {
            throw IllegalStateException("The recorder is not start yet.")
        }
        encoder?.pause()
        audioEncoder?.pause()
        status = Status.PREPARED
    }

    override fun stop() {
        if (Status.IDL == status) return
        GLEventPipeline.INSTANCE.queueEvent(Runnable {
            stopEncoder()
        })
        status = Status.IDL
    }

    override fun reset() {
        if (Status.IDL != status) {
            throw IllegalStateException("The recorder is prepared. You cannot reset a prepared recorder.")
        }
        context.reset()
    }

    private fun changeParamsCheck() {
        if (Status.IDL != status) {
            throw IllegalStateException("You cannot change a prepared recorder.")
        }
    }

    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    override fun setCameraIndex(index: CameraWrapper.CameraIndex) {
        if (Status.IDL == status) {
            context.cameraIndex = index
        } else if (Status.PREPARED == status || Status.STARTED == status) {
            cameraWrapper?.switchCamera(index)
        }
    }


    override fun enableHardware(enable: Boolean) {
        changeParamsCheck()
        context.codecType = if (enable) CodecContext.CodecType.HARD else CodecContext.CodecType.SOFT
    }

    override fun setOutputSize(width: Int, height: Int) {
        changeParamsCheck()
        context.video.width = width
        context.video.height = height
        if (0 != context.cameraSize.width && 0 != context.cameraSize.height) {
            context.check()
        }
    }
    override fun setPreviewDataType(type: CodecContext.PreviewDataType){
        context.previewDataType=type
    }
    override fun setVideoBitrate(bitrate: Int) {
        changeParamsCheck()
        context.video.bitrate = bitrate
    }

    /**
     * Set fps. It is highly recommended to set this value
     * @params fps 0 means auto
     */
    override fun setFps(fps: Int) {
        changeParamsCheck()
        context.video.fps = fps
    }

    override fun getWidth(): Int {
        return context.video.width
    }

    override fun getHeight(): Int {
        return context.video.height
    }

    override fun setFilter(filter: BaseFilter) {


    }

    override fun getFilter(): BaseFilter? {
        return null;
    }
    override fun setSurfaceView(sufaceView: SurfaceView) {
        this.sufaceView=sufaceView
    }
    override fun setPreviewDisplay(view: TextureView) {
        //空实现
    }
    override fun setOutputUri(uri: String) {
        changeParamsCheck()
        context.ioContext.path = uri
    }

    override fun setOritation(oritation: Int) {
        context.orientation=oritation
    }

    override fun onFrameAvailable(cameraTexture: SurfaceTexture?) {

    }
    private var needVideoCover=true
    private var isFirstFrame=true
    override fun onPreviewFrame(data: ByteArray, camera: Camera) {
        var dstData=data
        //输出宽高是1080*1920，但camera支持1920*1080，通过旋转实现，注意垂直旋转宽高对调
        //fixed by ZHG on 2020/4/21
        if (context.isVertical()){
            //转换前的宽高
            dstData=CodectUtil.nv21Rotate90(data,context.cameraSize.width,context.cameraSize.height)
        }
        var revert=true
        if (revert){
            dstData=CodectUtil.NV21_mirror(dstData,context.video.width,context.video.height)
        }
        if (needVideoCover&&status==Status.STARTED&&isFirstFrame&&dstData!=null){
            VideoCoverUtil.convertNv21ToJpeg(context.ioContext.path,dstData,context.video.width,context.video.height)
            isFirstFrame=false
        }
        encoder?.onPreviewFrame(dstData,camera)
    }

    private fun startPreview() {
        cameraWrapper?.start(surfaceHolder)
        cameraWrapper?.post(Runnable {
            startEncoder();
        })
    }

    private fun updatePreview(width: Int, height: Int) {
    }

    private fun startEncoder() {
        if (null == muxer) {
            muxer = MuxerFactory.getMuxer(context)
            muxer?.onMuxerListener = object : Muxer.OnMuxerListener {
                override fun onStart() {

                }

                override fun onError(error: Int, msg: String) {
                    onStateListener?.onError(error, msg)
                }
            }
        } else {
            muxer?.reset()
        }
        if (context.video.bitrate <= 0)
            setVideoBitrate(context.video.width * context.video.height * CodecContext.Video.MEDIUM * context.video.fps / 24)
        context.check()
        encoder = Encoder.Builder(context)
                .setOnPreparedListener(this)
                .build()
        if (null != muxer)
            encoder?.setOnSampleListener(muxer!!)
        audioEncoder = AudioEncoderImpl.fromDevice(context).apply {
            if (null != muxer)
                setOnSampleListener(muxer!!)
        }
        if (null != onStateListener)
            setOnStateListener(onStateListener!!)
    }

    override fun onPrepared(encoder: Encoder) {
        TLog.i("VideoRecorder prepared")
        status = Status.PREPARED
        onStateListener?.onPrepared(encoder)
    }

    override fun setOnStateListener(listener: VideoRecorder.OnStateListener) {
        this.onStateListener = listener
        encoder?.onRecordListener = onStateListener
    }

    override fun release() {
        stop()
        try {

            cameraWrapper?.release()
            cameraWrapper = null
        } catch (e: Exception) {
            e.printStackTrace()
        }
        context.release()
        GLEventPipeline.INSTANCE.quit()
    }

    private fun stopEncoder() {
        if (null != encoder) {
            encoder?.stop()
            encoder = null
        }
        if (null != audioEncoder) {
            audioEncoder?.stop()
            audioEncoder = null
        }
        if (null != muxer) {
            muxer?.release()
            muxer = null
        }
        onStateListener?.onStop()
    }
}